package club.ruanx.auth.vcode.factory;

import club.ruanx.auth.vcode.ValidateCode;
import club.ruanx.auth.vcode.enumeration.ValidateCodeType;
import club.ruanx.auth.vcode.exception.ValidateCodeException;
import club.ruanx.auth.vcode.repository.ValidateCodeRepository;
import club.ruanx.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.IOException;
import java.util.Map;

/**
 * @author 阮胜
 * @date 2018/9/30 14:28
 */
@SuppressWarnings("unchecked")
public abstract class AbstractValidateCodeProcessor<C extends ValidateCode> implements ValidateCodeProcessor {


    private static final String VALIDATE_CODE_GENERATOR_SUFFIX = "CodeGenerator";

    /**
     * 收集系统中所有的 {@link ValidateCodeGenerator} 接口的实现。
     */
    @Autowired
    private Map<String, ValidateCodeGenerator> validateCodeGeneratorMap;

    @Autowired
    private ValidateCodeRepository validateCodeRepository;

    @Override
    public void create(ValidateCodeType validateCodeType) throws IOException {
        C validateCode = generate(validateCodeType);
        save(validateCode, validateCodeType);
        send(validateCode);
    }

    /**
     * 生成校验码
     *
     * @return
     */
    private C generate(ValidateCodeType validateCodeType) {
        String generatorName = validateCodeType.name().toLowerCase() + VALIDATE_CODE_GENERATOR_SUFFIX;
        ValidateCodeGenerator validateCodeGenerator = validateCodeGeneratorMap.get(generatorName);
        if (validateCodeGenerator == null) {
            throw new ValidateCodeException("验证码生成器" + generatorName + "不存在");
        }
        return (C) validateCodeGenerator.generate();
    }

    /**
     * 保存校验码
     *
     * @param validateCode
     * @param validateCodeType
     */
    private void save(C validateCode, ValidateCodeType validateCodeType) {
        ValidateCode code = new ValidateCode(validateCode.getCode(), validateCode.getExpireTime());
        validateCodeRepository.save(code, validateCodeType);
    }

    /**
     * 发送校验码，由子类实现
     *
     * @param validateCode
     * @throws ValidateCodeException
     */
    protected abstract void send(C validateCode) throws ValidateCodeException, IOException;

    @Override
    public void validate(String vcode, ValidateCodeType validateCodeType) throws ValidateCodeException {
        if (StringUtils.isEmpty(vcode)) {
            throw new ValidateCodeException("验证码的值不能为空");
        }

        ValidateCode realCode = validateCodeRepository.get(validateCodeType);
        if (realCode == null) {
            throw new ValidateCodeException("验证码不存在");
        }

        if (realCode.isExpired()) {
            validateCodeRepository.remove(validateCodeType);
            throw new ValidateCodeException("验证码已过期");
        }

        if (!vcode.equalsIgnoreCase(realCode.getCode())) {
            throw new ValidateCodeException("验证码错误");
        }

        validateCodeRepository.remove(validateCodeType);
    }
}
